/*
This is part of Screenbar, which is based in part on the Litestep
shell source code.

Copyright (C) 2008-2009 Jim Babcock
Copyright (C) 1997-2009 The LiteStep Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#pragma once

/////////////////////////////////////////////////////////////////////////////

class FlowElement
	:public RectLayoutElement
{
public:
	FlowElement(string prefix);
	~FlowElement();
	
	bool changed(const LayoutCacheNode *node);
	void update(LayoutCacheNode *node);
	void deleteElementData(LayoutCacheNode *node, void *elementData);
	void getChildren(LayoutCacheNode *node, vector<LayoutLocation> &outChildren);
	
protected:
	bool resolveFinishedAnimations(vector<LayoutLocation> &group);
	bool startAnimations(vector<LayoutLocation> &group, vector<LayoutLocation> &newGroup);
	void cancelAnimations(vector<LayoutLocation> &group);
	bool matchElements(LayoutLocation &canonical, LayoutLocation &actual);
	bool isCreateAnimation(LayoutLocation &element);
	bool isDestroyAnimation(LayoutLocation &element);
	LayoutElement *startCreateAnimation(LayoutLocation created);
	LayoutElement *startDestroyAnimation(LayoutLocation destroyed);
	
	void parseChildTypes();
	
	Animation *createAnimation;
	Animation *destroyAnimation;
	
	vector<FlowChild*> childGroups;
	
	virtual ElementContext getChildContext(const ElementContext *parentContext)=0;
};

/////////////////////////////////////////////////////////////////////////////

class FlowChild
{
public:
	FlowChild(LayoutElement *childType);
	virtual void getChildren(const ElementContext *context, vector<LayoutLocation> &outChildren);
	virtual bool isConstant();
	
protected:
	LayoutElement *childType;
};

/////////////////////////////////////////////////////////////////////////////

class LinearFlow
	:public FlowElement
{
public:
	LinearFlow(string prefix);
	~LinearFlow();
	
	ElementSize getLength(const LayoutCacheNode *node);
	void arrangeChildren(LayoutCacheNode *container, vector<LayoutCacheNode*> &children);
	
protected:
	enum FlowDirection {
		flowVertical,
		flowHorizontal,
		flowDefault,
	};
	FlowDirection flowDirection;
	
	/// Get the per-row thickness of this flow in a given context
	int getRowThickness(const ElementContext *context);
	/// Get the number of rows in this flow. For counter-flows, this may
	/// depend on the number and sizes of children.
	int getRowCount(const LayoutCacheNode *node);
	/// Get the number of rows in this flow. This overload is not valid for
	/// counter-flows, since it does not receive information about children.
	int getRowCount(const ElementContext *context);
	/// Returns whether the flow arranges elements vertically, in the given
	/// context.
	bool isVertical(const ElementContext *context);
	/// Returns whether this is a counter-flow in the given context, that is,
	/// a vertical flow in a horizontal context or vise versa.
	bool isCounterFlow(const ElementContext *context);
	
	ElementContext getChildContext(const ElementContext *parentContext);
	
	void partitionRows(const vector<LayoutCacheNode*> &children, vector<int> &assignments, int rows, int rowLength, bool lengthFirst);
	void flowRow(const vector<LayoutCacheNode*> &children, vector<int> &lengths, int rowLength);
	
	bool variableRowCount;
	int rowThickness;
	int rowCount;
	bool lengthFirst;
};
